package com.zxjbyte.yiyi.framework.web.config;

import com.zxjbyte.yiyi.framework.common.constant.WebFilterOrderConstant;
import com.zxjbyte.yiyi.framework.web.filter.ApiCryptoFilter;
import com.zxjbyte.yiyi.framework.web.filter.YiyiRequestWrapperFilter;
import com.zxjbyte.yiyi.framework.web.handler.GlobalExceptionHandler;
import com.zxjbyte.yiyi.framework.web.handler.YiyiGlobalExceptionHandler;
import com.zxjbyte.yiyi.framework.web.event.ErrorLogListener;
import com.zxjbyte.yiyi.framework.web.xss.XssFilter;
import com.zxjbyte.yiyi.framework.web.xss.clean.DefaultXssCleaner;
import com.zxjbyte.yiyi.framework.web.xss.clean.IXssCleaner;
import com.zxjbyte.yiyi.module.system.api.log.ErrorLogApi;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.annotation.Resource;
import javax.servlet.Filter;

/**
 * @Author zhangxingjia
 * @Date 2023/3/1 15:26
 * @Version: 1.0
 */
@AutoConfiguration
@EnableConfigurationProperties({YiyiWebProperties.class, XssProperties.class, SwaggerProperties.class, ApiProperties.class})
public class YiyiWebAutoConfiguration implements WebMvcConfigurer {

    @Resource
    private XssProperties xssProperties;
    @Resource
    private ApiProperties apiProperties;
    @Resource
    private YiyiWebProperties yiyiWebProperties;

    @Bean
    public GlobalExceptionHandler globalExceptionHandler() {
        return new GlobalExceptionHandler();
    }

    @Bean
    public YiyiGlobalExceptionHandler yiyiGlobalExceptionHandler(YiyiWebProperties properties) {
        return new YiyiGlobalExceptionHandler(properties);
    }

    @Bean
    public ErrorLogListener errorLogListener(ErrorLogApi errorLogApi){
        return new ErrorLogListener(errorLogApi);
    }

    @Bean
    @ConditionalOnMissingBean
    public IXssCleaner xssCleaner(XssProperties xssProperties) {
        return new DefaultXssCleaner(xssProperties);
    }

    /**
     * 创建 CorsFilter Bean，解决跨域问题
     */
    @Bean
    public FilterRegistrationBean<CorsFilter> corsFilterBean() {
        // 创建 CorsConfiguration 对象
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOriginPattern("*"); // 设置访问源地址
        config.addAllowedHeader("*"); // 设置访问源请求头
        config.addAllowedMethod("*"); // 设置访问源请求方法
        // 创建 UrlBasedCorsConfigurationSource 对象
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config); // 对接口配置跨域设置
        return createFilterBean(new CorsFilter(source), WebFilterOrderConstant.CORS_FILTER);
    }

    @Bean
    public FilterRegistrationBean<YiyiRequestWrapperFilter> YiyiRequestWrapperFilter() {
        return createFilterBean(new YiyiRequestWrapperFilter(yiyiWebProperties), WebFilterOrderConstant.REQUEST_WRAPPER_FILTER);
    }

    @Bean
    public FilterRegistrationBean<ApiCryptoFilter> cryptoFilter(RequestMappingHandlerMapping requestMappingHandlerMapping) {
        return createFilterBean(new ApiCryptoFilter(apiProperties, yiyiWebProperties, requestMappingHandlerMapping), WebFilterOrderConstant.API_ENCRYPT_FILTER);
    }

    @Bean
    public FilterRegistrationBean<XssFilter> XssFilter(IXssCleaner xssCleaner) {
        return createFilterBean(new XssFilter(xssProperties, yiyiWebProperties, xssCleaner), WebFilterOrderConstant.XSS_FILTER);
    }

    public static <T extends Filter> FilterRegistrationBean<T> createFilterBean(T filter, Integer order) {
        FilterRegistrationBean<T> bean = new FilterRegistrationBean<>(filter);
        bean.setOrder(order);
        return bean;
    }
}
